﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "TriangleTemporaryDimensionHandler.h"
#include "IUiView.h"
#include "IUiDocumentViewManager.h"
#include "IActionManager.h"
#include "IAction.h"
#include "IGraphicsNodeGroup.h"
#include "TemporaryDimensionContext.h"
#include "Vector3dUtils.h"
#include "UiViewUtils.h"
#include "TemporaryDimensionCommonsUtils.h"

#include <QKeyEvent>

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

TriangleTemporaryDimensionHandler::TriangleTemporaryDimensionHandler(IUiView* pUIView)
    : TemporaryDimensionHandler(pUIView)
{
}


TriangleTemporaryDimensionHandler::~TriangleTemporaryDimensionHandler()
{
}

bool gcmp::TriangleTemporaryDimensionHandler::event(QEvent * pEvent)
{
    // 此方法应为入口键盘事件的处理函数
    if (pEvent->type() != QEvent::KeyPress)
    {
        return QObject::event(pEvent);
    }

    QKeyEvent* pKeyEvent = dynamic_cast<QKeyEvent*>(pEvent);
    DBG_WARN_AND_RETURN_UNLESS(pKeyEvent != nullptr, QObject::event(pEvent), L"难道pEvent不是键盘事件?",L"GDMPLab",L"2024-03-30");

    // 视图输入的入口
    // 当前Action启用了绘制助手时, 输入数字，激活视图内输入
    // 仅负责启动状态, 不负责状态启动后的事件处理
    if (IsInInputState() == false)
    {
        if (pKeyEvent->key() >= Qt::Key_A && pKeyEvent->key() <= Qt::Key_Z)
        {
            QString keyStr = pKeyEvent->text();
            ShowInputWidget(InputState::Width, false, true, keyStr.toStdWString());
            return true;
        }

        switch (pKeyEvent->key())
        {
            // 长度输入：
        case Qt::Key_0:
        case Qt::Key_1:
        case Qt::Key_2:
        case Qt::Key_3:
        case Qt::Key_4:
        case Qt::Key_5:
        case Qt::Key_6:
        case Qt::Key_7:
        case Qt::Key_8:
        case Qt::Key_9:
            ShowInputWidget(InputState::Width, false, true, QString::number(pKeyEvent->key() - Qt::Key_0).toStdWString());
            DBG_WARN_AND_RETURN_FALSE_UNLESS(m_pEditor != nullptr, L"m_pEditor is null",L"GDMPLab",L"2024-03-30");
            return m_pEditor->event(pEvent);

        case VK_NUMPAD0:
        case VK_NUMPAD1:
        case VK_NUMPAD2:
        case VK_NUMPAD3:
        case VK_NUMPAD4:
        case VK_NUMPAD5:
        case VK_NUMPAD6:
        case VK_NUMPAD7:
        case VK_NUMPAD8:
        case VK_NUMPAD9:
            ShowInputWidget(InputState::Width, false, true, QString::number(pKeyEvent->key() - VK_NUMPAD0).toStdWString());
            DBG_WARN_AND_RETURN_FALSE_UNLESS(m_pEditor != nullptr, L"m_pEditor is null",L"GDMPLab",L"2024-03-30");
            return m_pEditor->event(pEvent);

        case Qt::Key_Minus:
        case Qt::Key_onehalf:
        case Qt::Key(109):
            ShowInputWidget(InputState::Width, false, true, L"-");
            break;

        default:
            break;
        }
        IUiDocumentViewManager *pUiDocumentViewManager = IUiDocumentViewManager::Get();
        DBG_WARN_AND_RETURN_UNLESS(pUiDocumentViewManager != nullptr, QObject::event(pEvent), L"pUiDocumentViewManager is null",L"GDMPLab",L"2024-03-30");
        IUiView* pUIView = pUiDocumentViewManager->GetUiViewByRuntimeId(m_uiViewId);
        IActionManager::RefreshViewInput(pUIView);
    }
    return QObject::event(pEvent);
}

bool gcmp::TriangleTemporaryDimensionHandler::eventFilter(QObject * obj, QEvent * pEvent)
{
    if (pEvent->type() == QEvent::KeyPress)
    {
        QKeyEvent* key_event = dynamic_cast<QKeyEvent*>(pEvent);
        if (key_event)
        {
            IUiView* pUIView = IUiDocumentViewManager::Get()->GetUiViewByRuntimeId(m_uiViewId);
            DBG_WARN_AND_RETURN_UNLESS(pUIView, false, L"pUIView指针不能为空",L"GDMPLab",L"2024-03-30");
            QWidget* pViewWidget = QWidget::find((WId)pUIView->GetUiViewId());
            DBG_WARN_AND_RETURN_UNLESS(pViewWidget, false, L"pViewWidget指针不能为空",L"GDMPLab",L"2024-03-30");

            switch (key_event->key())
            {

            case Qt::Key_Return:
            case Qt::Key_Enter:
            case Qt::Key_Space:
            {
                OnEditorReturnPressed();
                return false;
            }

            case Qt::Key_Escape:
                HideInputWidget();
                return dynamic_cast<QObject*>(pViewWidget)->event(pEvent);

            case Qt::Key_Tab:
                OnEditorTabPressed();
                return true; // 切换输入状态, 拦截KeyEvent, 防止输入焦点被抢走

            default:
                break;
            }
        }
    }
    else if (pEvent->type() == QEvent::KeyRelease)
    {
        return true;
    }

    return QObject::eventFilter(obj, pEvent);
}

OwnerPtr<IGraphicsNodeGroup> gcmp::TriangleTemporaryDimensionHandler::GenerateGraphics(const ITemporaryDimensionContext * pCtx)
{
    OwnerPtr<IGraphicsNodeGroup> opGrepGroup = IGraphicsNodeGroup::Create();
    opGrepGroup->SetIsSnappable(false);

    DBG_WARN_AND_RETURN_UNLESS(pCtx, opGrepGroup, L"pCtx为空",L"GDMPLab",L"2024-03-30");
    const TriangleTemporaryDimensionContext* pTriangleCtx = dynamic_cast<const TriangleTemporaryDimensionContext*>(pCtx);
    DBG_WARN_AND_RETURN_UNLESS(pTriangleCtx, opGrepGroup, L"pRectangleCtx为空",L"GDMPLab",L"2024-03-30");

    Vector3d firstDockPos = pTriangleCtx->GetPt1();
    Vector3d secondDockPos = pTriangleCtx->GetPt2();
    Vector3d thirdDockPos = pTriangleCtx->GetPt3();
    m_coord = pTriangleCtx->GetCoord();
    SetUserCustomInput(pTriangleCtx->IsUserCustomInput());
    m_TmpDimStyle.LengthPrecision = pTriangleCtx->GetLengthPrecision();
    m_TmpDimStyle.AnglePrecision = pTriangleCtx->GetAnglePrecision();
    m_TmpDimStyle.RadiusPrecision = pTriangleCtx->GetRadiusPrecision();

    // 若始点与终点一致，则不绘制临时标注
    if (Vector3dUtils::IsEqual(firstDockPos, secondDockPos))
    {
        return opGrepGroup;
    }
    IUiDocumentViewManager *pUiDocumentViewManager = IUiDocumentViewManager::Get();
    DBG_WARN_AND_RETURN_UNLESS(pUiDocumentViewManager, opGrepGroup, L"pUiDocumentViewManager为空！",L"GDMPLab",L"2024-03-30");
    IUiView* pUIView = pUiDocumentViewManager->GetUiViewByRuntimeId(m_uiViewId);
    DBG_WARN_AND_RETURN_UNLESS(pUIView, opGrepGroup, L"pUIView为空！",L"GDMPLab",L"2024-03-30");
    IModelView* pModelView = pUIView->GetModelView();
    DBG_WARN_AND_RETURN_UNLESS(pModelView, opGrepGroup, L"pModelView为空！",L"GDMPLab",L"2024-03-30");

    double pixelLength = UiViewUtility::ComputeWorldWidthFromPixel(pUIView, 1);

    OwnerPtr<IGraphicsNodeGroup> opWidthDimensions = TemporaryDimensionCommonsUtils::GenerateWidthDimension(
        firstDockPos, secondDockPos, m_coord,
        m_InputState, m_TmpDimStyle, pixelLength, m_TmpDimData);
    opGrepGroup->AddChild(TransferOwnership(opWidthDimensions));

    OwnerPtr<IGraphicsNodeGroup> opHeightDimensions = TemporaryDimensionCommonsUtils::GenerateHeightDimension(
        secondDockPos ,firstDockPos, m_coord,
        m_InputState, m_TmpDimStyle, pixelLength, m_TmpDimData);
    opGrepGroup->AddChild(TransferOwnership(opHeightDimensions));

    return opGrepGroup;
}

bool gcmp::TriangleTemporaryDimensionHandler::WakeOn(int nKeyChar, bool isCtrlPressed, bool isAltPressed, bool isShiftPressed)
{
    // 如果不是数字, 不是comma，不是minus,不是字符串, 则不处理
    bool isNumKey = (Qt::Key_0 <= nKeyChar && nKeyChar <= Qt::Key_9);
    bool isNumPadKey = (VK_NUMPAD0 <= nKeyChar && nKeyChar <= VK_NUMPAD9);
    bool isCommaKey = (nKeyChar == VK_OEM_COMMA);
    bool isMinusKey = (nKeyChar == VK_OEM_MINUS) || (nKeyChar == VK_SUBTRACT);
    bool isCharKey = (IsUserCustomInput() ? (Qt::Key_A <= nKeyChar && nKeyChar <= Qt::Key_Z) : false);
    if (!isNumKey && !isNumPadKey && !isCommaKey && !isMinusKey && !isCharKey)
    {
        return false;
    }

    Qt::Key key = (Qt::Key)nKeyChar;

    // 为了让验证器支持快捷键（Alt+P), 临时在这里修改
    if (isAltPressed && key == Qt::Key_P)
        return false;

    Qt::KeyboardModifiers modifiers = Qt::NoModifier;
    if (isCtrlPressed)
    {
        modifiers |= Qt::ControlModifier;
    }
    if (isAltPressed)
    {
        modifiers |= Qt::AltModifier;
    }
    if (isShiftPressed)
    {
        modifiers |= Qt::ShiftModifier;
    }

    QKeyEvent keyEvent(QEvent::KeyPress, key, modifiers);
    return event(&keyEvent);
}

bool gcmp::TriangleTemporaryDimensionHandler::GetCoordinate(Coordinate3d &curCoord) const
{
    curCoord = m_coord;
    return true;
}

void gcmp::TriangleTemporaryDimensionHandler::ShowInputWidget(InputState enInputState, bool isTabShift, bool isOverrideValue, std::wstring inputValue)
{
    bool isInputStateValid = (enInputState == InputState::Width || enInputState == InputState::Height);
    DBG_WARN_AND_RETURN_VOID_UNLESS(isInputStateValid, L"InputState输入非法!",L"GDMPLab",L"2024-03-30");

    m_InputState = enInputState;

    if (m_InputState != InputState::None)
    {
        // 创建输入框
        if (!isTabShift)
        {
            CreateEditorWidget();
        }

        Vector3d editorWorldPos;
        switch (m_InputState)
        {
        case InputState::Width:
        {
            editorWorldPos = m_TmpDimData.WidthDimensionPosition;

            if (isTabShift)
            {
                if (isOverrideValue)
                {
                    m_pEditor->setText(QString::fromStdWString(inputValue));
                }
                else
                {
                    m_pEditor->setText(QString::number(m_TmpDimData.WidthValue, 'f', m_TmpDimStyle.LengthPrecision));
                }
                m_pEditor->selectAll();
            }
            else
            {
                m_pEditor->setText(QString::fromStdWString(inputValue));
            }

            break;
        }

        case InputState::Height:
        {
            editorWorldPos = m_TmpDimData.HeightDimensionPosition;

            if (isOverrideValue)
            {
                m_pEditor->setText(QString::fromStdWString(inputValue));
            }
            else
            {
                m_pEditor->setText(QString::number(m_TmpDimData.HeightValue, 'f', m_TmpDimStyle.LengthPrecision));
            }
            m_pEditor->selectAll();

            break;
        }

        default: break;
        }

        // 设置输入框位置
        SetEditorPosition(editorWorldPos);
        if (!IsUserCustomInput())
        // 输入合法性检查
        {
            std::unordered_map<const QLineEdit*, const ValidatorBase*> validators;
            validators.insert(std::make_pair(m_pEditor, &m_lenValidator));
            m_opValidateHelper->SetValidators(validators);
        }

        // 显示输入框
        m_pEditor->show();
        m_pEditor->setFocus();

        // 刷新当前视图
        IUiDocumentViewManager *pUiDocumentViewManager = IUiDocumentViewManager::Get();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDocumentViewManager, L"pUiDocumentViewManager输入非法!",L"GDMPLab",L"2024-03-30");
        IUiView* pUIView = pUiDocumentViewManager->GetUiViewByRuntimeId(m_uiViewId);
        IActionManager::RefreshViewInput(pUIView);
    }
}

void TriangleTemporaryDimensionHandler::OnEditorReturnPressed()
{
    if (!IsInInputState())
    {
        return;
    }

    ActionViewInput inputParam;
    bool isDouble = false;
    if (m_InputState == InputState::Width)
    {
        QString widthValue = m_pEditor->text();
        double widthDigit = widthValue.toDouble(&isDouble);
        inputParam.InputType = ActionViewInputType::Confirm_TriangleWidth;
        inputParam.InputVal = widthDigit;
    }
    else if (m_InputState == InputState::Height)
    {
        QString heightValue = m_pEditor->text();
        double heightDigit = heightValue.toDouble(&isDouble);
        inputParam.InputType = ActionViewInputType::Confirm_TriangleHeight;
        inputParam.InputVal = heightDigit;
    }
    else
    {
        DBG_WARN(L"m_enInputState怎么不是IS_Width或IS_Height?",L"GDMPLab",L"2024-03-30");
    }

    // 忽略非法输入
    if (!IsUserCustomInput() && (!isDouble || !m_lenValidator.ValidateValue(inputParam.InputVal)))
    {
        m_pEditor->selectAll();
        return;
    }

    HideInputWidget();

    // 这个方法会结束当前的IPickPointAction!! 连带结束当前Helper的生命周期!!! 后续不应该再添加任何代码!
    IUiDocumentViewManager *pUiDocumentViewManager = IUiDocumentViewManager::Get();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDocumentViewManager, L"pUiDocumentViewManager is null!",L"GDMPLab",L"2024-03-30");
    IUiView* pUIView = pUiDocumentViewManager->GetUiViewByRuntimeId(m_uiViewId);
    IActionManager::ProcessViewInput(pUIView, inputParam);
}

void gcmp::TriangleTemporaryDimensionHandler::OnEditorTabPressed()
{
    m_pEditor->clearFocus();
    IUiDocumentViewManager *pUiDocumentViewManager = IUiDocumentViewManager::Get();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDocumentViewManager, L"pUiDocumentViewManager is null!",L"GDMPLab",L"2024-03-30");
    IUiView* pUIView = pUiDocumentViewManager->GetUiViewByRuntimeId(m_uiViewId);
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_InputState == InputState::Width || m_InputState == InputState::Height, L"InputState输入非法!",L"GDMPLab",L"2024-03-30");
    ActionViewInput inputParam;
    if (m_InputState == InputState::Width)
    {
        // 确认宽度输入
        QString widthValue = m_pEditor->text();
        bool isDouble = false;
        double widthDigit = widthValue.toDouble(&isDouble);
        if(isDouble)
            inputParam.InputVal = widthDigit;
        else
            inputParam.InputString = widthValue.toStdWString();
        //ActionViewInput inputParam;
        inputParam.InputType = ActionViewInputType::Preview_TriangleWidth;
        
        // 忽略非法输入
        if (!IsUserCustomInput() && (!isDouble || !m_lenValidator.ValidateValue(inputParam.InputVal)))
        {
            m_pEditor->selectAll();
            return;
        }

        // 切换高度输入
        ShowInputWidget(InputState::Height, true);
    }
    else if (m_InputState == InputState::Height)
    {
        // 确认高度输入
        QString heightValue = m_pEditor->text();
        bool isDouble = false;
        double heightDigit = heightValue.toDouble(&isDouble);
        if (isDouble)
            inputParam.InputVal = heightDigit;
        else
            inputParam.InputString = heightValue.toStdWString();

        inputParam.InputType = ActionViewInputType::Preview_TriangleHeight;
        // 忽略非法输入
        if (!IsUserCustomInput() && (!isDouble || !m_lenValidator.ValidateValue(inputParam.InputVal)))
        {
            m_pEditor->selectAll();
            return;
        }
        // 切换宽度输入
        ShowInputWidget(InputState::Width, true);
    }

    IActionManager::ProcessViewInput(pUIView, inputParam);

    // 切换时用新的数据刷新当前视图
    IActionManager::RefreshViewInput(pUIView);
}
